package com.school.empsys.config;

import com.school.empsys.constants.UserStatus;
import com.school.empsys.mapper.PermissionMapper;
import com.school.empsys.mapper.RoleMapper;
import com.school.empsys.model.Permission;
import com.school.empsys.model.Role;
import com.school.empsys.model.User;
import com.school.empsys.service.UserService;
import com.school.empsys.utils.SpringUtil;
import com.school.empsys.utils.UserUtil;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


public class MyShiroRealm extends AuthorizingRealm {

    private static final Logger log = LoggerFactory.getLogger(MyShiroRealm.class);

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;

        String username = usernamePasswordToken.getUsername();
        UserService userService = SpringUtil.getBean(UserService.class);
        User user = userService.getUser(username);
        if (user == null) {
            throw new UnknownAccountException("用户不存在");
        }
        if (!user.getPassword().equals(userService.passwordEncoder(new String(usernamePasswordToken.getPassword()), user.getSalt()))) {
            throw new IncorrectCredentialsException("密码错误");
        }
        if (UserStatus.INVALID.getCode().equals(user.getStatus())) {
            throw new IncorrectCredentialsException("无效状态，请联系管理员");
        }
        if (UserStatus.LOCKED.getCode().equals(user.getStatus())) {
            if ((System.currentTimeMillis() - user.getUpdateTime().getTime()) / (1000 * 60 * 60 * 24) > 30) {
                throw new IncorrectCredentialsException("合同到期30天账号无效，请联系管理员");
            }
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(),
                ByteSource.Util.bytes(user.getSalt()), getName());
        UserUtil.setUserSession(user);
        return authenticationInfo;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        log.debug("权限配置");

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        User user = UserUtil.getCurrentUser();
        List<Role> roles = SpringUtil.getBean(RoleMapper.class).listByUserId(user.getId());
        Set<String> roleNames = roles.stream().map(Role::getName).collect(Collectors.toSet());
        authorizationInfo.setRoles(roleNames);
        List<Permission> permissionList = SpringUtil.getBean(PermissionMapper.class).listByUserId(user.getId());
        UserUtil.setPermissionSession(permissionList);
        Set<String> permissions = permissionList.stream().filter(p -> !StringUtils.isEmpty(p.getPermission()))
                .map(Permission::getPermission).collect(Collectors.toSet());
        authorizationInfo.setStringPermissions(permissions);
        return authorizationInfo;
    }

    /**
     * 重写缓存key，否则集群下session共享时，会重复执行doGetAuthorizationInfo权限配置
     */
    @Override
    protected Object getAuthorizationCacheKey(PrincipalCollection principals) {
        SimplePrincipalCollection principalCollection = (SimplePrincipalCollection) principals;
        Object object = principalCollection.getPrimaryPrincipal();

        if (object instanceof User) {
            User user = (User) object;
            return "authorization:cache:key:users:" + user.getId();
        }

        return super.getAuthorizationCacheKey(principals);
    }

}
